package main

import (
	"crypto/tls"
	"crypto/x509"
	"flag"
	"fmt"
	"html/template"
	"log"
	"net/http"

	"cert_utils"
)

var httpPort = flag.Int("http-port", 80, "The HTTP port.")
var httpsPort = flag.Int("https-port", 443, "The HTTPS port.")
var caCertFile = flag.String("ca-cert-file", "", "")
var certFile = flag.String("cert-file", "", "")
var keyFile = flag.String("key-file", "", "")
var authClient = flag.Bool("auth-client", false, "Whether to auth clients.")

type DownloadCAFileHandler struct {
	CACertFile string
	ServeMux   *http.ServeMux
}

const (
	DownloadCAPath   = "/download-ca"
	HomepageTemplate = `<script>
function gotoHTTPS() {
	window.location.protocol='https:'
}
</script>
<H1>
Please install <a href='{{.DownloadLink}}'>Certificate</a>
and go to <a onclick='gotoHTTPS()'>HTTPS</a>
</H1>`
)

func ServeHTTPHomePage(w http.ResponseWriter, r *http.Request) {
	log.Println("Serving homepage...")
	t, err := template.New("download-ca").Parse(HomepageTemplate)
	if err != nil {
		log.Fatalf("Failed to parse template: %s!", err)
	}
	t.ExecuteTemplate(w, "DownloadLink", DownloadCAPath)
}

func NewDownloadCAFileHandler(caCertFile string) DownloadCAFileHandler {
	serveMux := http.NewServeMux()
	serveMux.HandleFunc("/", ServeHTTPHomePage)
	serveMux.Handle(DownloadCAPath, FileHandler{FileName: caCertFile})
	return DownloadCAFileHandler{
		CACertFile: caCertFile,
		ServeMux:   serveMux,
	}
}

func (handler DownloadCAFileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	log.Println(r.URL.String())
	handler.ServeMux.ServeHTTP(w, r)
}

func main() {
	flag.Parse()

	var handler Handler
	if len(*caCertFile) > 0 && len(*certFile) > 0 && len(*keyFile) > 0 {
		go http.ListenAndServe(fmt.Sprintf(":%d", *httpPort), NewDownloadCAFileHandler(*caCertFile))

		log.Println("Starting secure server ...")
		certPool := x509.NewCertPool()
		certPool.AddCert(cert_utils.ReadCert(*caCertFile))
		tlsConfig := &tls.Config{
			ClientCAs: certPool,
		}
		if *authClient {
			tlsConfig.ClientAuth = tls.RequestClientCert
		}
		httpsServer := &http.Server{
			Addr:      fmt.Sprintf(":%d", *httpsPort),
			Handler:   handler,
			TLSConfig: tlsConfig,
		}
		err := httpsServer.ListenAndServeTLS(*certFile, *keyFile)
		if err != nil {
			log.Fatalf("Error: %s!\n", err)
		}
	} else {
		log.Println("Starting non-secure server!")
		http.ListenAndServe(
			fmt.Sprintf(":%d", *httpPort), handler)
	}
}
